package com.nettylearning.base.netty.io.selector;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author vince
 * @date 2021/7/18 21:46
 * @Version 1.0
 */
public class SelectorDemo {

    private static final int port = 8000;
    private Selector selector;
    private ByteBuffer buffer;
    private String content;

    /**
     * 注册事件
     *
     * @return
     * @throws IOException
     */
    private Selector getSelector() throws IOException {
        // 创建Selector对象
        Selector sel = Selector.open();
        // 创建可选择通道，并配置为非阻塞模式
        ServerSocketChannel server = ServerSocketChannel.open();
        server.configureBlocking(false);
        // 绑定通道到指定端口
        ServerSocket socket = server.socket();
        InetSocketAddress address = new InetSocketAddress(port);
        socket.bind(address);
        // 向Selector注册感兴趣的事件
        server.register(sel, SelectionKey.OP_ACCEPT);
        return sel;
    }

    /**
     * 开始监听
     */
    public void listen() throws IOException {
        selector = getSelector();
        System.out.println("listen on " + port);
        try {
            while (true) {
                // 该调用会阻塞，直到至少有一个事件发生
                selector.select();
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = keys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    process(key);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void process(SelectionKey key) throws IOException {
        buffer = ByteBuffer.allocate(1024);

        // 接受请求
        if (key.isAcceptable()) {
            ServerSocketChannel server = (ServerSocketChannel) key.channel();
            SocketChannel channel = server.accept();
            channel.configureBlocking(false);
            channel.register(selector, SelectionKey.OP_READ);
        }
        //  读数据
        else if (key.isReadable()) {
            SocketChannel channel = (SocketChannel) key.channel();
            int len = channel.read(buffer);
            if (len > 0) {
                buffer.flip();
                content = new String(buffer.array(), 0, len);
                SelectionKey sKey = channel.register(selector, SelectionKey.OP_WRITE);
                sKey.attach(content);
            } else {
                channel.close();
            }

            buffer.clear();
        }
        // 写事件
        else if (key.isWritable()) {
            SocketChannel channel = (SocketChannel) key.channel();
            content = (String) key.attachment();
            ByteBuffer block = ByteBuffer.wrap(("输出内容：" + content).getBytes());

            if (block != null) {
                channel.write(block);
            } else {
                channel.close();
            }
        }
    }
}
